﻿#region Using region
using System;
using System.Collections.Generic;
using System.Collections;
using System.Threading;
using System.Collections.Specialized;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
using Microsoft.Xna.Framework.GamerServices;


using JigLibX.Physics;
using JigLibX.Collision;
using JigLibX.Geometry;
using JigLibX.Math;
using JigLibX.Utils;
using sqengine.PhysicObjects;
using JigLibX.Vehicles;
using System.Diagnostics;



using sqengine.Engine;
using sqengine.Components;

using sqengine.Engine.Common;

using SqEngine.Components;
using SqEngine.Audio;
using SqEngine;


using PK3Model;
#endregion

namespace sqengine
{
    public enum MapLoadingState
    {
        None,
        Loading,
        JustLoaded,
        Loaded,
        Cleaning


    }

    partial class sqengine : Microsoft.Xna.Framework.Game
    {
        private string _default_map = "/Content/Maps/demo2.sqm";
        private string _map_to_load = "";
        private MapInfo _current_mapinfo;
        public MapInfo GetCurrentMapInfo { get { return _current_mapinfo; } }

        public MapLoadingState MapState = MapLoadingState.None;
        public string MapStateString;

        private Thread _loadmapthread;
        private Thread _cleanmapthread;

        private List<BasicObject> Worldobjlist = new List<BasicObject>();

        public void SetMapToLoad(string filename)
        {
            _map_to_load = filename;
        }

        private void UpdateMapStateStr(string state)
        {
            MapStateString = state;
        }


        public void PrepareCleanMapThread()
        {
            _cleanmapthread = new Thread(delegate()
                {
                    CleanMap();
                });
            _cleanmapthread.Name = "cleanmap thread";
            _cleanmapthread.Priority = ThreadPriority.Normal;
            _cleanmapthread.Start();
        }

        public void PrepareLoadMapThread(string mapname)
        {

            _loadmapthread = new Thread(delegate()
                {
                    LoadMap(mapname);
                });
            _loadmapthread.Name = "loadmap thread";
            _loadmapthread.Priority = ThreadPriority.Normal;
            _loadmapthread.Start();

        }

        public bool LoadMap(string filename)
        {
            int _delay = 500;

            contentloading_cmp.Start();
            MapObject curr_map = new MapObject();
            try
            {
                curr_map = SaveMan.LoadMap(filename);
                _current_mapinfo = new MapInfo();

                _current_mapinfo.Author = curr_map.MapInfo.Author;
                _current_mapinfo.MapName = curr_map.MapInfo.MapName;
                _current_mapinfo.Description = curr_map.MapInfo.Description;
                _current_mapinfo.BotsCount = curr_map.Bots.Count;
                _current_mapinfo.ObjectsCount = curr_map.WorldObjects.Count;

                //Init Player
                if (curr_map.PlayerStartPosition == Vector3.Zero)
                    curr_map.PlayerStartPosition = Vector3.Down * 12 + Vector3.Backward * 30.0f;
                InitPlayer(curr_map.PlayerStartPosition);
                Thread.Sleep(_delay);

                //Load Terrain

                LoadTerrain(curr_map.TerrainModel, curr_map.TerrainTexture);
                //PlaneObject planeObj = new PlaneObject(this, planeModel, 15.0f, adcontent, curr_map.TerrainTexture);
                // this.Components.Add(planeObj);

                UpdateMapStateStr("Loading Terrain");
                Thread.Sleep(_delay);

                //SkyDome 
                InitSkydome(curr_map.SkydomeTime);
                UpdateMapStateStr("Loading Skydome");
                Thread.Sleep(_delay);


                foreach (WorldObject wo in curr_map.WorldObjects)
                {
                    AddWorldObject(wo);
                    UpdateMapStateStr("Loading World Object: " + wo.BasicWorldObject);
                    Thread.Sleep(_delay);


                }

                foreach (WorldBot o_bot in curr_map.Bots)
                {
                    BotInfo bot = new BotInfo();
                    bot = SaveMan.LoadBot(adcontent.ContentRoot + o_bot.BotFile);
                    AddBot(bot.BotName, Content.RootDirectory + "\\" + bot.ModelName, o_bot.Orientation, Matrix.Identity, o_bot.Position, bot.Weapon, false, "");
                    UpdateMapStateStr("Loading Bot: " + bot.BotName);
                    Thread.Sleep(_delay);
                }

                mapinfo = new MapInfoDrawer(this, adcontent, string.Format("Author: {0} Map: {1}", curr_map.MapInfo.Author, curr_map.MapInfo.MapName));
                mapinfo.DrawOrder = 2;
                Components.Add(mapinfo);

                ConsoleSetVar(VAR_SQMAP_AUTHOR, curr_map.MapInfo.Author);
                ConsoleSetVar(VAR_SQMAP_NAME, curr_map.MapInfo.MapName);
                ConsoleSetVar(VAR_SQMAP_DESCRIPTION, curr_map.MapInfo.Description);


                _loadmapthread = null;
                MapState = MapLoadingState.JustLoaded;
                UpdateMapStateStr("");
                contentloading_cmp.Stop();

                return true;



            }
            catch (Exception ex)
            {

                throw new Exception(ex.Message);
                return false;

            }


        }

        public bool CleanMap()
        {
            int _delay = 100;
            //Clean bots
            MapState = MapLoadingState.Loading;
            contentloading_cmp.Start();
            UpdateMapStateStr("Cleaning game...");
            foreach (PK3_Model bot in BotList)
            {
                UpdateMapStateStr("Removing " + bot.BotPlayer.Name);
                this.Components.Remove(bot);
                Thread.Sleep(_delay);
            }

            //Clean Objs
            foreach (BasicObject obj in Worldobjlist)
            {
                UpdateMapStateStr("Removing " + obj.ToString());
                this.Components.Remove(obj);
                Thread.Sleep(_delay);
            }

            _cleanmapthread = null;

            UpdateMapStateStr("");
            contentloading_cmp.Stop();
            MapState = MapLoadingState.None;

            return true;
        }

        public void LoadTerrain(string t_model, string t_texture)
        {
            try
            {
                // some video card can't handle the >16 bit index type of the terrain

                terrainModel = adcontent.LoadModel(t_model);
                if (heightmapObj == null)
                {

                    heightmapObj = new HeightmapObject(this, terrainModel, Vector2.Zero, camera, adcontent, t_texture);
                    this.Components.Add(heightmapObj);

                }
                else
                {
                    heightmapObj.SetTexture(adcontent.LoadTexture2D(t_texture));
                   // heightmapObj.SetModel(terrainModel);
                }
            }
            catch
            {
                // if that happens just createa a ground plane 

                planeObj = new PlaneObject(this, planeModel, 15.0f, adcontent, t_texture);

                this.Components.Add(planeObj);

            }

        }




        public void AddWorldObject(WorldObject wObject)
        {

            BasicWorldObject bwo = SaveMan.LoadBasicWorldObject(adcontent.ContentRoot + wObject.BasicWorldObject);

            //Sfera
            switch (wObject.ObjectType)
            {
                case WorldObjectType.SphereObject:
                    {
                        SphereObject s_object = new SphereObject(this, bwo.Name, adcontent.LoadModel(Content.RootDirectory + "\\" + bwo.ObjectFilename), float.Parse(wObject.Params["radius"].ToString()), Matrix.Identity, wObject.Position, wObject.Mass, Content.RootDirectory + "\\" + bwo.Texture);
                        Components.Add(s_object);
                        Worldobjlist.Add(s_object);
                        break;
                    }
                case WorldObjectType.TarrainObject:
                    {
                        LoadTerrain(bwo.ObjectFilename, bwo.Texture);
                        break;
                    }
                case WorldObjectType.CapsuleObject:
                    {
                        CapsuleObject c_object = new CapsuleObject(this, bwo.Name, adcontent.LoadModel(Content.RootDirectory + "\\" + bwo.ObjectFilename), float.Parse(wObject.Params["radius"].ToString()), float.Parse(wObject.Params["lenght"].ToString()), Matrix.Identity, wObject.Position, Content.RootDirectory + "\\" + bwo.Texture);
                        Components.Add(c_object);
                        Worldobjlist.Add(c_object);
                        break;

                    }
                case WorldObjectType.BoxObject:
                    {
                        BoxObject b_object = new BoxObject(this, bwo.Name, adcontent.LoadModel(Content.RootDirectory + "\\" + bwo.ObjectFilename), (Vector3)(wObject.Params["sideLengths"]), Matrix.Identity, wObject.Position, Content.RootDirectory + "\\" + bwo.Texture);
                        Components.Add(b_object);
                        Worldobjlist.Add(b_object);
                        break;
                    }
                case WorldObjectType.PowerUpObject:
                    {
                        PowerUpObject p_object = new PowerUpObject(this, bwo.Name, adcontent.LoadModel(Content.RootDirectory + "\\" + bwo.ObjectFilename), (Vector3)(wObject.Params["sideLengths"]), Matrix.Identity, wObject.Position, Content.RootDirectory + "\\" + bwo.Texture, character.CharacterBody.CollisionSkin, wObject.Params);
                        //if (skydome != null)
                        //p_object.SetSkydome(skydome, skydome.GetDayTexture, skydome.GetSunsetTexture, skydome.GetNightTexture, adcontent.LoadEffect("Effects\\Sky"));
                        Components.Add(p_object);
                        Worldobjlist.Add(p_object);
                        break;
                    }
                case WorldObjectType.StaticObject:
                    {
                        StaticObject s_object = new StaticObject(this, bwo.Name, adcontent.LoadModel(Content.RootDirectory + "\\" + bwo.ObjectFilename), Matrix.Identity, wObject.Scale, wObject.Position, false);
                        Components.Add(s_object);
                        Worldobjlist.Add(s_object);
                        break;
                    }
                case WorldObjectType.MovableObject:
                    {
                        MovableObject s_object = new MovableObject(this, bwo.Name, adcontent.LoadModel(Content.RootDirectory + "\\" + bwo.ObjectFilename), Matrix.Identity, wObject.Scale, wObject.Position, false);
                        Components.Add(s_object);
                        //Worldobjlist.Add(s_object);
                        break;

                    }

                default:
                    break;
                //


            }
        }






    }
}
